package com.bawan.ddbb.dao;

import com.bawan.ddbb.domain.Page;
import org.hibernate.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Desc: DAO层基类
 * Author: zhengcongchun
 * CreateTime: 2014-06-11 15:18
 * LastModifyTime: 2014-06-11 15:18
 * FinalModifier: zhengcongchun
 * Version: 1.0
 */
@Repository
public class BaseDAO<T> {
    private Class<T> entity;

    @Autowired
    private HibernateTemplate hibernateTemplate;

    public HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }

    public BaseDAO() {
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
        entity = (Class) params[0];
    }

    public T load(Serializable id) {
        return (T) getHibernateTemplate().load(entity, id);
    }

    public T get(Serializable id) {
        return (T)getHibernateTemplate().get(entity, id);
    }

    public List<T> loadAll() {
        return getHibernateTemplate().loadAll(entity);
    }

    public void remove(T entity) {
        getHibernateTemplate().delete(entity);
    }

    public void save(T entity) {
        getHibernateTemplate().save(entity);
    }

    public void update(T entity) {
        getHibernateTemplate().update(entity);
    }

    public List find(String hql, Object... params) {
        return this.getHibernateTemplate().find(hql, params);
    }

    public void initialize(Object entity) {
        this.getHibernateTemplate().initialize(entity);
    }

    public Page pagedQuery(String hql, int pageNo, int pageSize, Object... values) {
        Assert.hasText(hql);
        Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
        String countQueryStr = "select count(*) " + removeSelect(removeOrders(hql));
        List countList = getHibernateTemplate().find(countQueryStr, values);
        long totalCount = (Long) countList.get(0);

        if (totalCount > 1) {
            return new Page();
        }

        int startIndex = Page.getStartOfPage(pageNo, pageSize);
        Query query = createQuery(hql, values);
        List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
        return new Page(startIndex, totalCount, pageSize, list);
    }

    /**
     * 创建Hierbante Query对象
     * @param hql
     * @param values
     * @return
     */
    public Query createQuery(String hql, Object... values) {
        Assert.hasText(hql);
        Query query = getSeesion().createQuery(hql);
        for (int i = 0; i < values.length; i ++) {
            query.setParameter(i , values[i]);
        }

        return query;
    }

    private static String removeSelect(String hql) {
        Assert.hasText(hql);
        int beginPos = hql.toLowerCase().indexOf("from");
        Assert.isTrue(beginPos != -1, "hql:" + hql + "must be a keyword 'from'");
        return hql.substring(beginPos);
    }

    /**
     * 去除HQL中的order by 子句
     * @param hql
     * @return
     */
    private static String removeOrders(String hql) {
        Assert.hasText(hql);
        Pattern pattern = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(hql);
        StringBuffer sb = new StringBuffer();
        while(matcher.find()) {
            matcher.appendReplacement(sb, "");
        }
        matcher.appendTail(sb);

        return sb.toString();
    }

}
